/*

<This Java Class is part of the jMusic API version 1.5, March 2004.>

Copyright (C) 2000 Andrew Brown

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or any
later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

package jm.gui.cpn;

import jm.JMC;
import jm.music.data.Phrase;

import java.awt.*;
//import jm.gui.cpn.CPNFrame;
//import javax.swing.*;

public class PianoStave extends Stave implements JMC {

    public PianoStave() {
        super();
        panelHeight = 160;
        this.setSize((int) (beatWidth * spacingValue), panelHeight);
    }

    public PianoStave(Phrase phrase) {
        super(phrase);
        panelHeight = 160;
        this.setSize((int) (beatWidth * spacingValue), panelHeight);
    }

    public void paint(Graphics graphics) {
        // set up for double buffering
        if (image == null) {
            image = this.createImage(this.getSize().width, this.getSize().height);
            g = image.getGraphics();
        }
        g.setFont(font);
        // keep track of the rhythmic values for bar lines
        double beatCounter = 0.0;
        // reset the chromatic vector
        previouslyChromatic.removeAllElements();
        // reste note position locations
        notePositions.removeAllElements();
        int keyAccidentals = 0;
        // add a title if set to be visible
        if (getDisplayTitle()) g.drawString(title, rightMargin, bPos - 10);
        // insert key signature if required
        int keyOffset = 0;
        // is the key signature using sharps or flats?
        if (keySignature > 0 && keySignature < 8) { // sharp
            for (int ks = 0; ks < keySignature; ks++) {
                // claulate position
                int keyAccidentalPosition = notePosOffset[sharps[ks] % 12] + bPos - 4 + ((5 - sharps[ks] / 12) * 24) + ((6 - sharps[ks] / 12) * 4);
                // draw sharp on treble
                g.drawImage(sharp, rightMargin + clefWidth + keyOffset, keyAccidentalPosition, this);
                // draw sharp on bass
                g.drawImage(sharp, rightMargin + clefWidth + keyOffset, keyAccidentalPosition + staveSpaceHeight * 7, this);
                // indent position
                keyOffset += 10;
                //add note to accidental vector
                int theModValue = sharps[ks] % 12;
                for (int pc = 0; pc < 128; pc++) {
                    if ((pc % 12) == theModValue) {
                        previouslyChromatic.addElement(new Integer(pc));
                        keyAccidentals++;
                    }
                }
                keySigWidth = keyOffset;
            }
        } else {
            if (keySignature < 0 && keySignature > -8) { // flat
                for (int ks = 0; ks < Math.abs(keySignature); ks++) {
                    // claulate position
                    int keyAccidentalPosition = notePosOffset[flats[ks] % 12] + bPos - 4 + ((5 - flats[ks] / 12) * 24) + ((6 - flats[ks] / 12) * 4);
                    // draw flat
                    g.drawImage(flat, rightMargin + clefWidth + keyOffset, keyAccidentalPosition, this);
                    // draw flat on bass stave
                    g.drawImage(flat, rightMargin + clefWidth + keyOffset, keyAccidentalPosition + staveSpaceHeight * 7, this);
                    // indent position
                    keyOffset += 10;
                    //add note to accidental vector
                    int theModValue = flats[ks] % 12;
                    for (int pc = 0; pc < 128; pc++) {
                        if ((pc % 12) == theModValue) {
                            previouslyChromatic.addElement(new Integer(pc));
                            keyAccidentals++;
                        }
                    }
                }
            }
        }
        keySigWidth = keyOffset + 3;

        // insert time signature if required
        if (metre != 0.0) {
            Image[] numbers = {one, two, three, four, five, six, seven, eight, nine};

            // top number
            g.drawImage(numbers[(int) metre - 1], rightMargin + clefWidth + keySigWidth, bPos + 13, this);
            g.drawImage(numbers[(int) metre - 1], rightMargin + clefWidth + keySigWidth, bPos + 13 + staveSpaceHeight * 6, this);
            //bottom number
            g.drawImage(four, rightMargin + clefWidth + keySigWidth, bPos + 29, this);
            g.drawImage(four, rightMargin + clefWidth + keySigWidth, bPos + 29 + staveSpaceHeight * 6, this);
            timeSigWidth = 30;
        } else timeSigWidth = 5;
        // set indent position for first note
        totalBeatWidth = rightMargin + clefWidth + keySigWidth + timeSigWidth;

        // draw notes and rests
        for (int i = 0; i < phrase.size(); i++) {
            int notePitchNum = (int) phrase.getNote(i).getPitch();
            // choose graphic
            chooseImage(notePitchNum, phrase.getNote(i).getRhythmValue(), 71, 60, 50);
            // reset pitch for rests

            // position?
            int pitchTempPos;
            if (notePitchNum == REST || phrase.getNote(i).getRhythmValue() == 0.0) { // rest or delete
                pitchTempPos = notePosOffset[71 % 12] + bPos - 4 + ((5 - 71 / 12) * 24) + ((6 - 71 / 12) * 4);
            } else {
                pitchTempPos = notePosOffset[notePitchNum % 12] + bPos - 4 + ((5 - notePitchNum / 12) * 24) +
                        ((6 - notePitchNum / 12) * 4);
            }

            // accidental?
            if (((notePitchNum % 12) == 1 || (notePitchNum % 12) == 3 || (notePitchNum % 12) == 6 ||
                    (notePitchNum % 12) == 8 || (notePitchNum % 12) == 10) && notePitchNum != REST &&
                    phrase.getNote(i).getRhythmValue() != 0.0) {
                if (keySignature > -1) {
                    g.drawImage(sharp, totalBeatWidth - 9, pitchTempPos, this);
                    // enter the note made sharp i.e, F for an F#
                    previouslyChromatic.addElement(new Integer(notePitchNum - 1));
                } else { // flat
                    pitchTempPos -= 4; // to show the note a semitone higher for flats
                    g.drawImage(flat, totalBeatWidth - 9, pitchTempPos, this);
                    previouslyChromatic.addElement(new Integer(notePitchNum + 1));
                    notePitchNum++; // assume it is a semitone higher for legerlines etc...
                }
            } else { // check for a natural
                // check vector
                int size = previouslyChromatic.size();
                for (int j = 0; j < size; j++) {
                    Integer temp = (Integer) previouslyChromatic.elementAt(j);
                    if (temp.intValue() == notePitchNum && notePitchNum != REST &&
                            phrase.getNote(i).getRhythmValue() != 0.0) {
                        // add natural
                        g.drawImage(natural, totalBeatWidth - 7, pitchTempPos, this);
                        // remove element if not in key signature
                        if (j > keyAccidentals - 1) previouslyChromatic.removeElementAt(j);
                        j = size;
                    }
                }
            }

            // draw note/rest
            g.drawImage(currImage, totalBeatWidth, pitchTempPos, this);
            // store position in a vector
            notePositions.addElement(new Integer(totalBeatWidth));
            notePositions.addElement(new Integer(pitchTempPos));
            //System.out.println("Position "+i+" "+totalBeatWidth + " "+ pitchTempPos);

            if (dottedNote) {
                boolean dotFlag = true;
                for (int l = 0; l < lineNotes.length; l++) {
                    if (lineNotes[l] + 12 == notePitchNum || lineNotes[l] + 36 == notePitchNum ||
                            lineNotes[l] + 60 == notePitchNum || lineNotes[l] + 84 == notePitchNum ||
                            lineNotes[l] + 108 == notePitchNum || notePitchNum == REST) {
                        g.drawImage(dot, totalBeatWidth + 1, pitchTempPos - 4, this);
                        dotFlag = false;
                        l = lineNotes.length;
                    }
                }
                if (dotFlag) g.drawImage(dot, totalBeatWidth + 1, pitchTempPos, this);
            }
            // leger lines middle C
            if (notePitchNum == 60 || notePitchNum == 61 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 52, totalBeatWidth + 12, bPos + 52);
            }

            // leger lines down
            if (notePitchNum <= 40 && notePitchNum > -1 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 100, totalBeatWidth + 12, bPos + 100);
            }
            if (notePitchNum <= 37 && notePitchNum > -1 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 108, totalBeatWidth + 12, bPos + 108);
            }
            if (notePitchNum <= 34 && notePitchNum > -1 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 116, totalBeatWidth + 12, bPos + 116);
            }
            if (notePitchNum <= 30 && notePitchNum > -1 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 124, totalBeatWidth + 12, bPos + 124);
            }
            if (notePitchNum <= 27 && notePitchNum > -1 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 132, totalBeatWidth + 12, bPos + 132);
            }
            // leger lines up
            if (notePitchNum >= 81 && notePitchNum < 128 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos + 4, totalBeatWidth + 12, bPos + 4);
            }
            if (notePitchNum >= 84 && notePitchNum < 128 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos - 4, totalBeatWidth + 12, bPos - 4);
            }
            if (notePitchNum >= 88 && notePitchNum < 128 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos - 12, totalBeatWidth + 12, bPos - 12);
            }
            if (notePitchNum >= 91 && notePitchNum < 128 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos - 20, totalBeatWidth + 12, bPos - 20);
            }
            if (notePitchNum >= 95 && notePitchNum < 128 && phrase.getNote(i).getRhythmValue() != 0.0) {
                g.drawLine(totalBeatWidth - 3, bPos - 28, totalBeatWidth + 12, bPos - 28);
            }

            // increment everything
            totalBeatWidth += currBeatWidth;
            dottedNote = false;
            // quantised to semiquvers!
            // (int)((phrase.getNote(i).getRhythmValue()/0.25) * 0.25);
            beatCounter += (int) (phrase.getNote(i).getRhythmValue() / 0.25) * 0.25;

            // add bar line if required
            if (metre != 0.0) {
                if ((beatCounter % metre) == 0.0) {
                    g.drawLine(totalBeatWidth, bPos + 12, totalBeatWidth, bPos + 44 + staveSpaceHeight * 6);
                    // add bar numbers?
                    if (barNumbers) g.drawString("" + (int) (beatCounter / metre + 1 + phrase.getStartTime()),
                            totalBeatWidth - 4, bPos);
                    totalBeatWidth += 12;
                }
            }
        }

        // draw treble stave
        for (int i = 0; i < 5; i++) {
            g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight),
                    totalBeatWidth, (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight));
        }

        // draw bass stave
        for (int i = 6; i < 11; i++) {
            g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight),
                    totalBeatWidth, (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight));
        }
        // draw neext note stave area
        // draw stave
        g.setColor(Color.lightGray);
        for (int i = 0; i < 5; i++) {
            g.drawLine(totalBeatWidth,
                    (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight),
                    totalBeatWidth + 50,
                    (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight));
        }
        for (int i = 6; i < 11; i++) {
            g.drawLine(totalBeatWidth,
                    (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight),
                    totalBeatWidth + 50,
                    (bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i * staveSpaceHeight));
        }
        g.setColor(Color.black);
        // add Clefs
        g.drawImage(trebleClef, rightMargin + 7, bPos - 4, this);
        g.drawImage(bassClef, rightMargin + 7, bPos + staveSpaceHeight * 6, this);
        
        /* Draw completed buffer to g */

        graphics.drawImage(image, 0, 0, null);
        // clear image
        // clear
        g.setColor(this.getBackground());
        g.fillRect(0, 0, getSize().width, getSize().height);
        g.setColor(this.getForeground());
        //repaint();
        //g.dispose();
    }
}
        
